﻿using Ajr.DigitaPlatform.Common;
using Ajr.DigitaPlatform.DeviceAccess;
using Ajr.DigitaPlatform.DeviceAccess.Base;
using Ajr.DigitaPlatform.IDataAccess;
using Ajr.DigitaPlatform.Models;
using Ajri.DigitaPlatform.Entities;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.CommandWpf;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace Ajr.DigitaPlatform.ViewModels
{
    public class MainViewModel : ViewModelBase
    {
        private int _viewBlur = 0;

        public int ViewBlur
        {
            get { return _viewBlur; }
            set { Set(ref _viewBlur, value); }
        }
        public UserModel GlobalUserInfo { get; set; } = new UserModel();
        public RelayCommand<object> SwitchPageCommand { get; set; }
        private object _viewContent;

        public object ViewContent
        {
            get { return _viewContent; }
            set { Set(ref _viewContent, value); }
        }
        public List<MenuModel> Menus { get; set; }
        public List<DeviceItemModel> DeviceList { get; set; }

        //Monitor
        public List<RankingItemModel> RankingList { get; set; }
        public List<MonitorWarnningModel> WarnningList { get; set; }
        public RelayCommand ComponentsConfigCommand { get; set; }
        ILocalDataAccess _localDataAccess;
        public MainViewModel(ILocalDataAccess localDataAccess)
        {
            _localDataAccess = localDataAccess;
            if (!IsInDesignMode)
            {
                // 主窗口数据
                Menus = new List<MenuModel>();
                Menus.Add(new MenuModel
                {
                    IsSelected = true,
                    MenuHeader = "监控",
                    MenuIcon = "\ue639",
                    TargetView = "MonitorPage"
                });
                Menus.Add(new MenuModel
                {

                    MenuHeader = "趋势",
                    MenuIcon = "\ue61a",
                    TargetView = "TrendPage"
                });
                Menus.Add(new MenuModel
                {
                    MenuHeader = "报警",
                    MenuIcon = "\ue60b",
                    TargetView = "AlarmPage"
                });
                Menus.Add(new MenuModel
                {
                    MenuHeader = "报表",
                    MenuIcon = "\ue703",
                    TargetView = "ReportPage"
                });
                Menus.Add(new MenuModel
                {
                    MenuHeader = "配置",
                    MenuIcon = "\ue60f",
                    TargetView = "SettingsPage"
                });

                ShowPage(Menus[0]);
                SwitchPageCommand = new RelayCommand<object>(ShowPage);

                #region 用气排行
                string[] quality = new string[] { "车间-1", "车间-2", "车间-3", "车间-4",
                "车间-5" };

                Random random = new Random();
                RankingList = new List<RankingItemModel>();
                foreach (var q in quality)
                {
                    RankingList.Add(new RankingItemModel()
                    {
                        Header = q,
                        PlanValue = random.Next(100, 200),
                        FinishedValue = random.Next(10, 150),
                    });
                }
                #endregion
                #region 设备提醒
                WarnningList = new List<MonitorWarnningModel>()
                {
                  new MonitorWarnningModel{Message= "爱吉尔PLT-01：保养到期11111111111111111111111111111111111112222222222222",
                      DateTime=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") },
                  new MonitorWarnningModel{Message= "爱吉尔PLT-01：故障",
                      DateTime=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") },
                  new MonitorWarnningModel{Message= "爱吉尔PLT-01：保养到期",
                      DateTime=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") },
                  new MonitorWarnningModel{Message= "爱吉尔PLT-01：保养到期",
                      DateTime=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") },
                  new MonitorWarnningModel{Message= "爱吉尔PLT-01：保养到期",
                      DateTime=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") },
                  new MonitorWarnningModel{Message= "爱吉尔PLT-01：保养到期",
                      DateTime=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") },
                  new MonitorWarnningModel{Message= "爱吉尔PLT-01：保养到期",
                      DateTime=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }
                };
                #endregion
                ComponentsConfigCommand = new RelayCommand(ShowConfig);
                // 初始化组件信息
                this.ComponentsInit();
                //开始获取设备数据
                this.Monitor();
            }
        }
        CancellationTokenSource cts = new CancellationTokenSource();
        List<Task> tasks = new List<Task>();

        private void Monitor()
        {
            //通过统一的接口获取通信对象（提供对应的属性）
            //获取对象后，进行方法的调用
            //多设备请求：1、设备集合依次轮询（一个设备处理完后，关闭连接，再开下个连接-短链接）  ModBusRtu 串口总线
            //2、每个设备单独监视(每个设备一个线程,一个连接打开后后，直到应用退出在关闭连接)
            //场景：设备 分离从一个设备中转  不允许多个连接
            //需要解决传输对象公用问题 ---之后多线程同时处理 对象 上锁
            Communication communication = new Communication();

            foreach (var item in DeviceList)
            {
                //如果没有配置相关数据，不执行监视
                if (item.PropList.Count == 0 || item.VariableList.Count == 0) continue; 
                //更具配置信息，创建协议执行对象
                var result_eo = communication.GetExecuteObject(
                    item.PropList.Select(p =>
                    new DevicePropItemEntity { PropName = p.PropName, PropValue = p.PropValue }
                    ).ToList());
                if ( !result_eo.Status)
                {
                    //异常提示信息
                    //item.ErrorMessage.add(result_eo.Message);
                    continue;
                }
                //根据协议对象，创建循环监视线程
                    var task =    Task.Run(async () =>
                    {
                        //处理 刷新频率
                    int delay = 500;
                        //刷新频率
                    var dv = item.PropList.FirstOrDefault(p => p.PropName == "RefreshRate");
                    if (dv != null)
                    {
                            //转化成功，配置500
                        int.TryParse(dv.PropValue, out delay);
                    }
                        //将当前设备中的所有点位数据 提供到Read方法
                        //ushort ("Sytem.UInt16")
                        //
                        List<VariableProperty> variables = item.VariableList.Select(v => new VariableProperty
                        {
                            VarId = v.VarNum,
                            VarAddr = v.VarAddress,
                            ValueType = Type.GetType("System."+v.VarType)
                        }).ToList();
                        //循环逻辑
                        Result<List<CommAddress>> result_addr = result_eo.Data.GroupAddress(variables);
                        if (!result_addr.Status)
                        {
                            // 异常提示信息
                            //item.ErrorMessages.Add(result_eo.Message);
                            return;
                        }
                        //异步线程没有被取消则一直循环监视
                        while (!cts.IsCancellationRequested)
                    {
                        await Task.Delay(delay);
                            //处理数据
                           var result_value =  result_eo.Data.Read(result_addr.Data); //目前，里面做打包
                            if(result_value.Status)
                            {
                                //解析数据
                                foreach (var ma in result_addr.Data)
                                {
                                    foreach (var vv in ma.Variables)
                                    {
                                        var dataBytes = vv.ValueBytes;
                                        var id = vv.VariableId;
                                        var dVar = item.VariableList.FirstOrDefault(v => v.VarNum == id);//设备的变量记录
                                        // vp.VarId
                                        //vp.ValueBytes
                                        //需要进一步处理
                                        Result<object> result_data = communication.ConvertType(dataBytes, Type.GetType("System." + dVar.VarType));
                                        if (!result_data.Status)
                                        {
                                            //item.IsWarning = true;
                                            //item.WarningMessage = result_data.Message;
                                            continue;
                                        }
                                        dVar.Value = result_data.Data;
                                        //v.Value = BitConverter.ToUInt16(dataBytes, 0);

                                        // 字节序
                                    }

                                }

                                //目前，通信平台中返回相关数据的字节


                                //后续，希望封装第三方库，返回数据
                            }
                    }
                        result_eo.Data.Dispose();
                    },cts.Token);
                  tasks.Add(task);
                }
               
               
            }

        
        private void ComponentsInit()
        {
            var ds = _localDataAccess.GetDevices().Select(d =>
            {
                return new DeviceItemModel()
                {
                    X = double.Parse(d.X),
                    Y = double.Parse(d.Y),
                    Z = int.Parse(d.Z),
                    Width = double.Parse(d.W),
                    Height = double.Parse(d.H),
                    DeviceType = d.DeviceTypeName,
                    DeviceNum = d.DeviceNum,
                    FlowDirection = int.Parse(d.FlowDirection),
                    Rotate = int.Parse(d.Rotate),

                    PropList = new ObservableCollection<DevicePropModel>(
                        d.Props.Select(dp => new DevicePropModel
                        {
                            PropName = dp.PropName,
                            PropValue = dp.PropValue,
                        })),

                    VariableList = new ObservableCollection<VariableModel>(
                        d.Vars.Select(dv => new VariableModel
                        {
                            VarNum = dv.VarNum,
                            VarName = dv.Header,
                            VarAddress = dv.Address,
                            Offset = dv.Offset,
                            Modulus = dv.Modulus,
                            VarType = dv.VarType,
                        }))
                };
            });
            DeviceList = ds.ToList();

            this.RaisePropertyChanged(nameof(DeviceList));
        }

        private void ShowPage(object obj)
        {
            // Bug：对象会重复创建，需要处理
            //79行解决

            var model = obj as MenuModel;
            if (model != null)
            {
                if (ViewContent != null && ViewContent.GetType().Name == model.TargetView) return;
                //反射获取正在运行目录下的项目
                Type type = Assembly.Load("Ajr.DigitaPlatform.Views")
                    .GetType("Ajr.DigitaPlatform.Views.Pages." + model.TargetView)!;

                //输出对应的userControl实例
                ViewContent = Activator.CreateInstance(type)!;
            }
        }
        //打开配置窗口
        private void ShowConfig()
        {
            if (GlobalUserInfo.UserType > 0)
            {
                this.ViewBlur = 5;

                // ConfigViewModel configViewModel = new ConfigViewModel();
                // 可以打开编辑   启动窗口   主动
                if (ActionManager.ExecuteAndResult<object>("AAA", null))
                {
                    // 刷新   配置文件/数据库
                    //1.修改后 保存成功 2.修改 保存失败 3.
                    //添加一个等待页面(预留)
                    //可能会有耗时控件
                    //1.先把异步线程停止
                    cts.Cancel();
                    //2.将保存的异步线程重新启动
                    Task.WaitAll(tasks.ToArray());
                    //重新刷新cts状态
                    cts = new CancellationTokenSource();
                    tasks.Clear();
                    ComponentsInit();
                }
                this.ViewBlur = 0;

            }
            else
            {
                // 提示没有权限操作
            }
        }

        public  override void Cleanup()
        {
            base.Cleanup();
        }

    }
}